#include "stdafx.h"
#include <MyViews/ZoomTool.h>
#include <MyViews/ZoomView.h>
#include "std_min_max.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// ZoomTool

IMPLEMENT_DYNAMIC(ZoomTool, Tool)

ZoomTool::ZoomTool(ZoomView & owner)
	: m_Owner(owner), m_RubberRect(&owner)
{
	VERIFY (m_CursorZoom = AfxGetApp()->LoadCursor("ZoomTool_CursorZoom"));
	VERIFY (m_CursorNoZoom = AfxGetApp()->LoadCursor("ZoomTool_CursorNoZoom"));
	VERIFY (m_CursorZoomIn = AfxGetApp()->LoadCursor("ZoomTool_CursorZoomIn"));
	VERIFY (m_CursorZoomOut = AfxGetApp()->LoadCursor("ZoomTool_CursorZoomOut"));

	m_State = none;
}

ZoomTool::~ZoomTool()
{
}	 

void ZoomTool::Show()
{

}

void ZoomTool::Hide()
{
	m_State = none;
}

void ZoomTool::ZoomIn(CPoint p)
{
	m_Owner.ZoomBy(2.f, &p);
}

void ZoomTool::ZoomOut(CPoint p)
{
	m_Owner.ZoomBy(0.5f, &p);
}

void ZoomTool::ZoomFit()
{
	m_Owner.ZoomFit();
}

BEGIN_MESSAGE_MAP(ZoomTool, Tool)
	//{{AFX_MSG_MAP(ZoomTool)
		// NOTE - the ClassWizard will add and remove mapping macros here.
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// ZoomTool message handlers

void ZoomTool::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	CRect r;
	m_Owner.GetClientRect(&r);

	CPoint p = r.CenterPoint();

	switch (nChar) {
	case VK_ADD:
		m_State = in;
		ZoomIn(p);
		break;
	case VK_SUBTRACT:
		m_State = out;
		ZoomOut(p);
		break;
	case VK_MULTIPLY:
		m_State = none;
		ZoomFit();
	}
	m_Owner.UpdateCursor();
}

void ZoomTool::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	m_State = none;
	m_Owner.UpdateCursor();
}

void ZoomTool::OnLButtonDown(UINT nFlags, CPoint p)
{
	m_State = in;
	m_Owner.SetFocus();
	m_RubberRect.PinDown(p);
	m_Owner.SetCapture();
	m_Owner.UpdateCursor();
}

void ZoomTool::OnLButtonUp(UINT nFlags, CPoint p)
{
	if (m_State == in) {
		if (m_RubberRect.GetBox().Width() <= 4 && m_RubberRect.GetBox().Height() <= 4) 
			ZoomIn(p);
		else {
			//bench's position of rubber rect's center
			point<float> fp = m_Owner.ClientToBench(m_RubberRect.GetBox().CenterPoint());

			//old position of client center
			CRect r;
			m_Owner.GetClientRect(&r);
			p = r.CenterPoint();
			//new client center after scaling should be BenchToClient(fp)

			rect<float> bench = m_Owner.ClientToBench(m_RubberRect.GetBox());
			CSize client = m_Owner.GetClientSize();

			float fScaleX, fScaleY;
			fScaleX = float(client.cx - 2) / bench.width();
			fScaleY = float(client.cy - 2) / bench.height();

			float fScale = std::min(fScaleX, fScaleY);

			m_Owner.SetScale(fScale);
			m_Owner.Superpose(fp, p);
		}
	}
	m_RubberRect.SetVisible(false);
	m_State = none;
	ReleaseCapture();
	m_Owner.UpdateCursor();
}

void ZoomTool::OnMouseMove(UINT nFlags, CPoint p)
{
	if (m_State == in &&
		m_Owner.GetCapture() == &m_Owner) //mouse is not captured if user sets m_State=in due to '+' key down
	{
		m_RubberRect.SetVisible(true);
		m_RubberRect.Stretch(p);
	}
}

void ZoomTool::OnRButtonDown(UINT nFlags, CPoint p)
{
	m_State = out;
	m_Owner.SetFocus();
	m_Owner.UpdateCursor();
}

void ZoomTool::OnRButtonUp(UINT nFlags, CPoint p)
{
	ZoomOut(p);
	m_State = none;
	m_Owner.UpdateCursor();
}

bool ZoomTool::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
	HCURSOR cur = 0;


	switch (m_State) {
	case none:
		cur = m_CursorZoom;
		break;
	case in:
		cur = (m_Owner.GetScale() == m_Owner.m_MaxScale ? 
			m_CursorNoZoom : m_CursorZoomIn);
		break;
	case out:
		cur = (m_Owner.GetScale() == m_Owner.m_MinScale ? 
			m_CursorNoZoom : m_CursorZoomOut);
		break;
	}
	SetCursor(cur);

	return true;
}
